
# ifndef __DFX_VERTEX_FORMAT_H__
# define __DFX_VERTEX_FORMAT_H__

# include "dfxCore.h"

namespace DFX
{
    enum VERTEX_ELEMENT_FORMAT
    {
        VERTEX_ELEMENT_FORMAT_FLOAT1,
        VERTEX_ELEMENT_FORMAT_FLOAT2,
        VERTEX_ELEMENT_FORMAT_FLOAT3,
        VERTEX_ELEMENT_FORMAT_FLOAT4,
        VERTEX_ELEMENT_FORMAT_HALF_FLOAT2,
        VERTEX_ELEMENT_FORMAT_HALF_FLOAT4,
        VERTEX_ELEMENT_FORMAT_RGBA64,
        VERTEX_ELEMENT_FORMAT_COLOR,
        VERTEX_ELEMENT_FORMAT_RGBA32,
        VERTEX_ELEMENT_FORMAT_SHORT2,
        VERTEX_ELEMENT_FORMAT_SHORT4,
        VERTEX_ELEMENT_FORMAT_BYTE4,
        VERTEX_ELEMENT_FORMAT_MAX
    };

    enum VERTEX_ELEMENT_USAGE
    {
        VERTEX_ELEMENT_USAGE_POSITION,
        VERTEX_ELEMENT_USAGE_NORMAL,
        VERTEX_ELEMENT_USAGE_COLOR,
        VERTEX_ELEMENT_USAGE_TANGENT,
        VERTEX_ELEMENT_USAGE_BINORMAL,
        VERTEX_ELEMENT_USAGE_DEPTH,
        VERTEX_ELEMENT_USAGE_BLENDWEIGHT,
        VERTEX_ELEMENT_USAGE_BLENDINDICES,
        VERTEX_ELEMENT_USAGE_TEXCOORD,
        VERTEX_ELEMENT_USAGE_POINTSIZE,
        VERTEX_ELEMENT_USAGE_FOG,
        VERTEX_ELEMENT_USAGE_SAMPLE,
        VERTEX_ELEMENT_USAGE_TESS_FACTOR
    };

    class DFX_EXPORT VertexElement
    {
    private:

        String                  mName;
        UInt16				    mOffset;
        UInt8					mIndex;
        VERTEX_ELEMENT_FORMAT	mFormat;
        VERTEX_ELEMENT_USAGE	mUsage;

    public:

        VertexElement(const String &name, UInt8 index, UInt16 offset, 
            VERTEX_ELEMENT_FORMAT format, VERTEX_ELEMENT_USAGE usage);

        const String& GetName() const
        {
            return mName;
        }

        UInt8 GetIndex() const
        {
            return mIndex;
        }

        UInt16 GetOffset() const
        {
            return mOffset;
        }

        VERTEX_ELEMENT_FORMAT GetFormat() const
        {
            return mFormat;
        }

        VERTEX_ELEMENT_USAGE GetUsage() const
        {
            return mUsage;
        }

        UInt32 GetSize() const;
    };

    typedef std::vector<VertexElement>		VertexElementArray;
    typedef std::map<String, VertexElement>	VertexElementStringMap;

    class DFX_EXPORT VertexFormat
    {
    private:

        VertexElementArray		mElements;
        UInt32					mSize;
        bool					mNeedUpdate;

    public:

        VertexFormat()
            : mSize(0), mNeedUpdate(true)
        {
        }

        ~VertexFormat()
        {
            Clear();
        }

        UInt32 GetVertexSize() const
        {
            if (mNeedUpdate)
                const_cast<VertexFormat*>(this)->Update();

            return mSize;
        }

        const VertexElementArray& GetElements() const
        {
            return mElements;
        }

        UInt32 GetNumElements() const
        {
            return mElements.size();
        }

        VertexElement* GetElement(UInt32 index);

        void AddElement(const VertexElement &element);
        void AddElement(const String &name, UInt8 index, UInt16 offset, 
            VERTEX_ELEMENT_FORMAT format, VERTEX_ELEMENT_USAGE usage);        

        void Update();
        void Clear();
    };

    typedef std::vector<VertexFormat*>              VertexFormatArray;
    typedef std::vector<VertexFormat*>::iterator    VertexFormatIterator;
}

# endif